/**********************************************************************************************
 * ______________________________________Exchange Shares______________________________________*
 **********************************************************************************************/

/*
PURPOSE: 

    The goal of this script is to calculate date-exchange level volume data for 2007 - 2018 
    from the Daily TAQ Trades File. We then create two separate datasets as output:
    one that contains daily volume shares and another that contains weekly volume shares 
    for every exchange.
    
    A row in the output of this script would be, for example in the weekly volume shares
    dataset, the share of volume transacted on NYSE during the the week of January 1, 2010.
    
PRIMARY INPUT: 
    
    The Daily TAQ Trades file is a dataset where a row is a single trade. Each row contains
    the date the trade was executed, the timestamp (millisecond precision before 8/3/2015,
    microsecond precision afterwards), the symbol root (name) and symbol suffix (equity class),
    the exchange where the trade was executed, the trade price and quantity,
    and a trade sale condition that describes the context of the trade (e.g. a stock-option trade,
    a next day trade, an intermarket sweep).
    
APPROACH: 

    We calculate volume from the subset of "regular" trades in the Daily TAQ Trades file.
    Regular trades are:
    
    1. The trade had a valid record and was not been cancelled or corrected.
    2. The trade occurred on exchange and not on FINRA's Alternative Display Facility
    3. The trade occurred during regular trading hours (adjusted for halfdays)
    4. The trade took place under normal conditions. We identify such trades labelled by the 
    trade sale condition as "Regular", "Odd Lot", "Intermarket Sweep", and any valid combination 
    of the three. We exclude all trades that include any other trade conditions.
    For more context on the trade sale condition code, please consult "PLACEHOLDER README"
    
    The procedure can be described as follows.
    
    1. First, we load the Daily TAQ Trades file for a single day and identify regular trades 
    with the flag f_Vol_Regular.
    
    2. Second, we group the trades by exchange and add up all the volume transacted on each
    exchange for that day. We end up with a row for each exchange.
    
    3. We repeat the same procedure for every day in every month in every year from 2007 to 2018.
    
    4. Once we have the date-exchange level volume from 2007 to 2018, we produce date-exchange
    level shares (the share of volume transacted on NYSE on 5/8/2010 for example) and week-exchange
    level shares.
    
SUPPLEMENTAL INPUT FILES: 
    
    "Server_Directories.xlsx"
    "Holidays.xlsx"
    
INSTRUCTION:

    Find the wrapper "Exchange_Shares.sh". Make sure that in this file, the argument after
    "-sysparm" is "2007_2018". Submit the wrapper on the WRDS server.
*/

/*
 ****************************************************************************************
 * ______________________________________INITIALIZE______________________________________
 ****************************************************************************************
 */
/*
 * WRDS LIBRARY:
 *
 * This sets up the wharton library, which allows us to access the CRSP and TAQ datasets.
 */
%include '/wrds/lib/utility/wrdslib.sas';
options mprint;

/*
 * IMPORT INPUT PARAMETERS:
 * 
 * Make sure to enter the path to your input directory below.
 */
proc import datafile="/home/uchicago/eche/sasuser.v94/WRDS/Input/Server_Directories" out= server_directories dbms = xlsx replace;
run;
proc import datafile="/home/uchicago/eche/sasuser.v94/WRDS/Input/Holidays" out= holidays dbms = xlsx replace;
run;

data holiday_import;
    set holidays;
    
    if holiday = "New_Years" then do; call symput('New_Years', trim(date)); end;
    if holiday = "MLK_Day" then do; call symput('MLK_Day', trim(date)); end;
    if holiday = "Presidents_Day" then do; call symput('Presidents_Day', trim(date)); end;
    if holiday = "Good_Friday" then do; call symput('Good_Friday', trim(date)); end;
    if holiday = "Memorial_Day" then do; call symput('Memorial_Day', trim(date)); end;
    if holiday = "Independence_Day" then do; call symput('Independence_Day', trim(date)); end;
    if holiday = "Labor_Day" then do; call symput('Labor_Day', trim(date)); end;
    if holiday = "Thanksgiving" then do; call symput('Thanksgiving', trim(date)); end;
    if holiday = "Christmas" then do; call symput('Christmas', trim(date)); end;
    if holiday = "Hurricane_Sandy" then do; call symput('Hurricane_Sandy', trim(date)); end;
    if holiday = "Halfdays" then do; call symput('Halfdays', trim(date)); end;
run;

data directory_import;
    set server_directories;
    
    if directory = "user_directory" then do; call symput('userdir', trim(path)); end;
    if directory = "volume_directory" then do; call symput('voldir', trim(path)); end;
    if directory = "temp_directory" then do; call symput('tempdir', trim(path)); end;
run;

/**
 * Directories:
 *
 * Sets up the directories according to the paths in the "Server_Directories.xlsx" file.
 */
libname userdir &userdir;
libname voldir &voldir;
libname tempdir &tempdir;

/* Set user_path for import/export 
 * We need to dequote the path passed in from "Server_Directories.xlsx"
 */

%let user_path  = %qsysfunc(dequote(&userdir));

/**********************************************************************************************
 *______________________________________GLOBAL VARIABLES______________________________________*
 **********************************************************************************************/

/* 
 * Specify the year for which to calculate volume.
 * Uncomment this line to run from the SAS Studio website.
 */
%let sysparm = 2007_2018;

/* Obtain the years from the wrapper. */
%let START_YEAR_INPUT = %scan(&SYSPARM, 1, '_');
%let END_YEAR_INPUT = %scan(&SYSPARM, 2, '_');

/* This handles the case where the end year input is the same as the start year. */
%if %sysfunc(INPUTn(&END_YEAR_INPUT, 1.))=. %then %do;
    %let END_YEAR_INPUT = &START_YEAR_INPUT;
%end;

/* Trade beginning and end times. */
%let trade_begin_time = "09:30:00.000"t;
%let trade_end_time_reg = "16:00:00.000"t;
%let trade_end_time_halfday = "13:00:00.000"t;

/*
 ***********************************************************************************
 * ______________________________________MACRO______________________________________
 ***********************************************************************************
 */
/*
 * _MACRO_ : DailyExchangeVolume(YYYYMMDD)
 *
 * PARAM: YYYYMMDD: This is the day for which the volume is calculated.
 * 
 * This Macro takes the TAQ Volume for a given day, specified by YYYYMMDD, 
 * and sums up the volume executed at each exchange
 *
 * OUTPUT: Ex_Volume_&YYYYMMDD, the exchange level volume data for that day.
 */
%Macro DailyExchangeVolume(YYYYMMDD);
    /**
     * INPUT: taqmsec.ctm_&YYYYMMDD, Daily TAQ Trades File
     *
     * Loads the Daily TAQ Trades file and identifies valid trades with the regular volume flag.
     * Later, we aggregate volume from these trades. 
     *
     * OUTPUT: _trades, Daily TAQ Trades File with volume flags
     */
    data _trades;
        set taqmsec.ctm_&YYYYMMDD.;
        
        /* Re-label trades with exchange code 'Q' to exchange code 'T' (combine Nasdaq codes). */
        if ex = "Q" then ex = "T";
        
        /*
         * ______________________________________REGULAR VOLUME______________________________________
         * Here we identify all the trades that we consider as regular volume.
         * 
         * 1. f_Valid_Record : f_Valid_Record indicates that the entry in the trades dataset 
         * contains the correct record of that trade.
         * 
         * 2. f_On_Exchange : f_On_Exchange indicates that the trade was executed on an exchange 
         * and not on FINRA's Alternative Display Facility.
         * 
         * 3. f_Regular_Hours : f_Regular_Hours indicates that the trade was executed during 
         * regular trading hours, which are adjusted during halfdays. This also excludes trades
         * conducted on holidays.
         * 
         * 4. f_Regular_Trade : f_Regular_Trade indicates that the trade took place under regular 
         * conditions. These are trades labelled as "Regular Trades", "Intermarket Sweeps", 
         * and "Odd Lot", and any valid combination of the three.
         */
        
        /* f_Valid_Record
         *
         * Trade Correction Codes:
         *
         * "00" : Regular trade which was not corrected, changed or signified as cancel or error.
         * "01" : Original trade which was late corrected (this record contains the original time
         * and the corrected data for the trade).
         */
        
        f_Valid_Record = tr_corr in ("00", "01");
        
        /*
         * f_On_Exchange
         * 
         * Exchange Code: "D": FINRA Alternative Display Facility. 
         */
        f_On_Exchange = ex ne "D";

        /* f_Regular_Hours
         *
         * Regular trading hours are between 9:30 am and 4:00 pm. Execeptions are holidays and halfdays. 
         * Incidents (e.g. Flash Crash, Hurricane Sandy) are dropped in the MonthlyVolume_Interval Macro.
         *
         * Holidays:
         * New Years, MLK, Presidents Day, Good Friday, Memorial Day, Independence Day, Labor Day, 
         * Thanksgiving, Christmas.
         *
         * Halfdays:
         * Usually around December 24, November 27, and July 3, right before major holidays.
         * On a half day, trading occurs from 9:30 am to 1:00 pm.
         */
        f_New_Years_Day = date in &New_Years;
        f_MLK_Day=date in &MLK_Day;
        f_Presidents_Day=date in &Presidents_Day;
        f_Good_Friday=date in &Good_Friday;
        f_Memorial_Day=date in &Memorial_Day;
        f_Indpdnce_Day=date in &Independence_Day;
        f_Labor_Day=date in &Labor_Day;
        f_Thanksgiving=date in &Thanksgiving;
        f_Christmas_Day=date in &Christmas;
        f_Holiday=f_New_Years_Day or f_MLK_Day or f_Presidents_Day or f_Good_Friday 
            or f_Memorial_Day or f_Indpdnce_Day or f_Labor_Day or f_Thanksgiving or 
            f_Christmas_Day;
        
        /* Halfdays */
        f_Halfday=date in &Halfdays;

        f_Regular_Hours=((~f_Holiday      &
                            ~f_Halfday      &
                            time_m > &trade_begin_time  &
                            time_m < &trade_end_time_reg) or
                          (~f_Holiday      &
                            f_Halfday      &
                            time_m > &trade_begin_time &
                            time_m < &trade_end_time_halfday));

        /* f_Regular_Trade
         *
         * Trade Condition Codes:
         *
         * '@' = Regular Trade
         * 'I' = Odd lot
         * 'FI' = Intermarket Sweep and Odd Lot (CTA Only)
         * 'F' = Intermarket Sweep (CTA Only)
         * '@F' = Regular Trade and an Intermarket Sweep (UTP Only)
         * '@FI' = Regular Trade, Intermarket Sweep and Odd Lot (UTP Only)
         * '@I' = Regular Trade and Odd Lot (UTP Only)
         * '' = Regular Trade (UTP Only)
         *
         * The UTP only and CTA only notes are observations in 2015 but not requirements for the code.
         */
        
        /* 
         * We remove the white space in the trade condition 
         * to identify the code combinations for our regular trades.
         */
        tr_scond_no_space = compress(tr_scond);
        
        f_Regular_Trade = tr_scond_no_space = "@" or
                               tr_scond_no_space = "I" or
                               tr_scond_no_space = "F" or
                               tr_scond_no_space = "FI" or
                               tr_scond_no_space = "@F" or
                               tr_scond_no_space = "@FI" or
                               tr_scond_no_space = "@I" or
                               tr_scond_no_space = "E" or
                               tr_scond_no_space = "FE" or
                               tr_scond = "";

        /* Combine flags to create the regular volume flag. */
        f_Vol_Regular = f_Valid_Record &
                        f_On_Exchange &
                        f_Regular_Hours &
                        f_Regular_Trade;
        
        format time_m time12.3;
    run;
    
    /* Sort the trades data by exchange */
    proc sort data=_trades out=_trades;
        by ex;
    run;

    /**
     * INPUT: taqmsec.ctm_&YYYYMMDD., symbol-date-exchange trades data
     *
     * Group trades by exchange and count up all regular volume 
     * transacted on each exchange.
     * 
     * Note that this will create a record for each exchange only if an exchange has
     * non-zero trading during the day. When we produce daily and weekly volume shares
     * we create a null entry an exchange if it didn't experience any trading this day.
     *
     * OUTPUT: _trades, symbol-date-exchange-trades data with volume flags
     */
    data Ex_Volume_&YYYYMMDD.;
        set _trades;
        by ex;
        
        /* 
         * We set up an array to store the volume measures for each exchange.
         * The first entry stores the share volume, the second entry stores the dollar volume.
         * We save these numbers in an array for code simplification.
         */
        array Regular_Volume(2);
        
        /* Retain saves the volume variables across iterations */
        retain Regular_Volume1-Regular_Volume2 .;
        
        /* 
         * For the first trade of the symbol-interval-exchange combination, 
         * we reset the volume variables to 0.
         */
        if first.ex then do;
            Regular_Volume(1) = 0;
            Regular_Volume(2) = 0;
        end;
        
        /* Sum up the share and dollar volume from regular trades. */
        if f_Vol_Regular then do;
            Regular_Volume(1) = sum(Regular_Volume(1), size);
            Regular_Volume(2) = sum(Regular_Volume(2), size * price);
        end;
        
        /* 
         * We only save the row of the last trade of trades data
         * to get a single row for each date-exchange combination.
         */
        if last.ex;
        Volume_S = Regular_Volume(1);
        Volume_D = Regular_Volume(2);
        output;
        
        keep date ex Volume_:;
    run;

    /* Save daily file to the volume directory */
    data voldir.Daily_Ex_Volume_&YYYYMMDD.;
        set Ex_Volume_&YYYYMMDD.;
    run;

    /* Delete daily files from work */
    proc datasets library = work;
        delete Ex_Volume_&YYYYMMDD.;
        delete _trades;
        run;
    quit;
%Mend;

/*
 * _MACRO_ : MonthlyExchangeVolume(YYYYMM)
 * 
 * PARAM: YYYYMM: The month for which this macro aggregates volume.
 *
 * REQUIRES: DailyExchangeVolume
 *
 * This Macro takes the TAQ Volume for a given month, specified by YYYYMM, and iterates through all the days in that month,
 * specified from the "TAQMSEC" library. It iterates through all the days in the month, and for each day applies the DailyVolume_Interval Macro.
 *
 * OUTPUT: Ex_Volume_&YYYYMM, the symbol-date-exchange level volume data for that month. Also saves it to your volume directory.
 *
 */
%Macro MonthlyExchangeVolume(YYYYMM);
    /*
     * INPUT: sashelp.vtable, this is a table containing a row for all available datasets.
     * There's a column for "libname", the library the dataset belongs to, and "memname", 
     * which is the name of the dataset.
     * 
     * Extracts the Daily TAQ Trades filenames for each day in the month.
     * 
     * OUTPUT: Daily_Trades_Filenames, list of filenames
     */
    proc sql;
        create table Daily_Trades_Filenames
        as select 
        libname, 
        memname 
        from sashelp.vtable where 
        libname = "TAQMSEC" and memname like "CTM_&YYYYMM.%";
    quit;

    /*
     * Counts the number of filenames in Daily_Trades_Filenames as "nobs".
     * Save a list of the filenames as "file_list", separated by "|". 
     * These are used to iterate over the valid trading days within the month.
     */
    proc sql print;
        select count(*) into: nobs from Daily_Trades_Filenames;
        select memname into: file_list separated by '|' from Daily_Trades_Filenames;
    quit;

    /* Loop over days and run DailyVolume_Interval for each valid trading day. */    
    %do i=1 %to &nobs.;
    
        /* Get the name of the days and the daily file names in the month. */
        %let ctm_file  = %scan(%quote(&file_list.), &i., '|');
        
        /* The date is extracted from the filename by taking the content after "CTM_". */
        %let YYYYMMDD  = %substr(&ctm_file., 5, 8);

        /* Apply DailyVolume Macro. */
        %DailyExchangeVolume(YYYYMMDD = &YYYYMMDD.);
    %end;

    /*** Save the monthly files to the volume directory. ***/
    data voldir.Month_Ex_Volume_&YYYYMM.;
        set voldir.Daily_Ex_Volume_&YYYYMM.:;
    run;
        
    /* Delete the daily files in the volume directory. */
    proc datasets library = voldir;
        delete Daily_Ex_Volume_&YYYYMM.:;
        run;
    quit;
%Mend;

/*
 * _MACRO_ : AnnualExchangeVolume(YYYY)
 *
 * PARAM: YYYY: The year for which this macro aggregates volume.
 * 
 * REQUIRES: MonthlyExchangeVolume
 *
 * This Macro takes the TAQ Volume for a given year, specified by YYYYMM, and iterates through all the months in that year.
 * For every month it applies the AnnualExchangeVolume Macro.
 *
 * Since Reg NMS was implemented in October 2007, for that year we start from October.
 *
 * OUTPUT: Ex_Volume_&YYYY, the date-exchange level volume data for that year.
 *
 */
%Macro AnnualExchangeVolume(YYYY);
    %let month_list = 01|02|03|04|05|06|07|08|09|10|11|12;
    
    /* 
     * Iterate across all months in the year for years after 2007.
     * Run MonthlyExchangeVolume for every month in the year.
     */
    %if (&YYYY. > 2007) %then %do;
        %do m=1 %to 12;
            %let month = %scan(%quote(&month_list.), &m., '|');
            %put ##### Processing &month. &YYYY.;
            %MonthlyExchangeVolume(YYYYMM=&YYYY.&month.);
        %end;
    %end;
    
    /* For 2007, start data collection in october when REG NMS starts. */      
    %if (&YYYY.=2007) %then %do;
        %do m=10 %to 12;
            %let month = %scan(%quote(&month_list.), &m., '|');
            %put ##### Processing &month. &YYYY.;
            %MonthlyExchangeVolume(YYYYMM=&YYYY.&month.);
        %end;
    %end;
    
    /*** Save the annual files to the volume directory. ***/
    data voldir.Annual_Ex_Volume_&YYYY.;
        set voldir.Month_Ex_Volume_&YYYY.:;
    run;
        
    /* Delete the monthly files in the volume directory. */
    proc datasets library = voldir;
        delete Month_Ex_Volume_&YYYY.:;
        run;
    quit;
%Mend;

/*
 * _MACRO_ : PeriodExchangeVolume(start_year, end_year)
 * 
 * PARAM: start_year: The first year of the period for which this macro iterates AnnualVolume
 *        end_year: The last year of the period for which this macro iterates AnnualVolume
 *
 * REQUIRES: AnnualExchangeVolume
 *
 * This macro iterates and executes the AnnualExchangeVolume macro 
 * for all the years in the period you give it.
 *
 */

%Macro PeriodExchangeVolume(start_year, end_year);
    
    /* Attach the underscore to the end year, for the filename. */
    %let period_ending = _&end_year.;
    
    /* 
     * Iterate through the years in the range set by start_year and end_year.
     * Run the AnnualExchangeVolume macro.
     */
    %do y=&start_year %to &end_year;
        %AnnualExchangeVolume(&y.);
    %end;
%Mend;

%Macro Compile_Period_Volume(start_year, end_year);

    /* Attach the underscore to the end year, for the filename. */
    %let period_ending = _&end_year.;
    
    /* Set all the annual exchange files into one dataset. */
    %do t=&start_year %to &end_year;
        %if &t = &start_year %then %do;
            data Ex_Volume_&start_year.&period_ending.;
                set voldir.Annual_Ex_Volume_&t.;
            run;
        %end;
        %else %do;
            proc append base= Ex_Volume_&start_year.&period_ending.
                data=voldir.Annual_Ex_Volume_&t.;
            run;
        %end;
    %end;
    
    /* Export to the tempdir */
    data tempdir.Ex_Volume_&start_year.&period_ending.;
        set Ex_Volume_&start_year.&period_ending.;
    run;
%Mend;

/*
 * _MACRO_ : Daily_Volume_Shares(period)
 * 
 * PARAM: period, the period of the volume data. A year or an interval.
 *
 * REQUIRES: PeriodExchangeVolume
 *
 * Daily_Volume_Shares computes the daily volume shares of each exchange using the annual volume files created by PeriodExchangeVolume.
 * This macro also creates a record for every exchange present in the data from 2007 to 2018 for every day, even if a particular exchange
 * did not have experience any trading that day. In such cases, we set the volume of those records to nulls.
 *
 */
%Macro Daily_Volume_Shares(period);
    /** 
     * INPUT: Ex_Volume_&period, date-exchange volume loaded from the volume directory. 
     * 
     * Load the date-exchange level volume from the volume directory.
     * This is volume for the whole period. In this exercise, this is "2007_2018".
     * 
     * OUTPUT: Input_Ex_Volume, date-exchange volume
     */
    data Input_Ex_Volume;
        set tempdir.Ex_Volume_&period.;
    run;
    
    /** 
     * INPUT: Input_Ex_Volume, date-exchange volume
     * 
     * Loads the date-exchange level volume as a sql table.
     * 
     * OUTPUT: Exchange_Daily_Volume, date-exchange volume
     */
    proc sql;
        create table Exchange_Daily_Volume
        as select
        date,
        ex,
        sum(Volume_S)   as Volume_S,
        sum(Volume_D)   as Volume_D
        from Input_Ex_Volume
        group by date, ex;
    quit;
    
    /*
     * INPUT: Exchange_Daily_Volume, week-exchange volume
     * 
     * This builds the list of all exchanges in the TAQ data, as well as a list of all dates in the TAQ Data.
     * Then it creates a list of all permutations of these exchanges and dates.
     * 
     * Output: Key_Ex, list of exchanges in the TAQ Data
     *         Key_Date, list of dates in the TAQ Data
     *         Key_Date_Ex, list of all possible exchange-date combinations in TAQ Data
     */
    proc sql;
        create table Key_Ex     as select distinct ex,                   1 as key from Exchange_Daily_Volume;
        create table Key_Date   as select distinct date,                 1 as key from Exchange_Daily_Volume;
        create table Key_Date_Ex
        as select
        a.date, b.ex, 1 as key
        from Key_Date as a
        full join Key_Ex as b
        on a.key = b.key;
    quit;
    
    /*
     * INPUT: Exchange_Daily_Volume, week-exchange volume
     *        Key_Date_Ex, list of all possible exchange-date combinations in TAQ Data
     * 
     * This merges the date-exchange volume dataset onto Key_Date_Ex, the list of all possible exchange-date combinations.
     * Exchange-date combinations that did not experience trading get a volume of 0.
     * 
     * OUTPUT: Exchange_Daily_Volume_All, week-exchange volume
     */
    proc sql;
        create table Exchange_Daily_Volume_All
        as select
        a.*,
        b.Volume_S,
        b.Volume_D
        from Key_Date_Ex as a
        left join Exchange_Daily_Volume as b
         on a.date       = b.date
          & a.ex         = b.ex;
    quit;

    /** 
     * INPUT: Exchange_Daily_Volume, date-exchange volume
     * 
     * Calculates the volume shares by dividing each exchange's volume by the total volume executed that day.
     * 
     * OUTPUT: Raw_Daily_Shares_2007_2018, date-exchange volume and volume shares
     */
    proc sql;
        create table Ex_Daily_Shares_&period.
        as select
        a.date,
        a.ex,
        a.Volume_S,
        a.Volume_D,
        a.Volume_S   / sum(a.Volume_S)   as Regular_Sh_S,
        a.Volume_D   / sum(a.Volume_D)   as Regular_Sh_D
        from Exchange_Daily_Volume_All as a
        group by date;
    quit;
    
    /* Export to the user directory */
    data tempdir.Ex_Daily_Shares_&period.;
        set Ex_Daily_Shares_&period.;
    run;
  
    /* Export to the user directory as a csv */
    proc export data= Ex_Daily_Shares_&period.
        outfile = "&user_path./Ex_Daily_Shares_&period..csv"
        dbms = csv replace;
    run;
%Mend;

/*
 * _MACRO_ : Weekly_Volume_Shares(period)
 * 
 * PARAM: period, the period of the volume data. A year or an interval.
 *
 * REQUIRES: PeriodExchangeVolume
 *
 * Weekly_Volume_Shares computes the weekly volume shares of each exchange using the annual volume files created by PeriodExchangeVolume.
 * This macro also merges the volume and volume share data on a list of all possible week-exchange combinations in the TAQ.
 *
 */
%Macro Weekly_Volume_Shares(period);
    /** 
     * INPUT: Ex_Volume_&period, date-exchange volume loaded from the volume directory. 
     * 
     * Load the date-exchange level volume from the volume directory.
     * This is volume for the whole period. In this exercise, this is "2007_2018".
     * 
     * OUTPUT: Input_Ex_Volume, date-exchange volume
     */
    data Input_Ex_Volume;
        set tempdir.Ex_Volume_&period.;
    run;

    /** 
     * INPUT: Input_Ex_Volume, date-exchange volume
     * 
     * Loads the date-exchange level volume as a sql table.
     * Then obtain the week from the date and produce a week-exchange level volume dataset.
     * 
     * OUTPUT: Exchange_Weekly_Volume, week-exchange volume
     */
    proc sql;
        create table Exchange_Weekly_Volume
        as select
        intnx('WEEK', date, 0) as week format = YYMMDDN8.,
        ex,
        sum(Volume_S)   as Volume_S,
        sum(Volume_D)   as Volume_D
        from Input_Ex_Volume
        group by week, ex;
    quit;
    
    /*
     * INPUT: Exchange_Weekly_Volume, week-exchange volume
     * 
     * This builds the list of all exchanges in the TAQ data, as well as a list of all dates in the TAQ Data.
     * Then it creates a list of all permutations of these exchanges and dates.
     * 
     * Output: Key_Ex, list of exchanges in the TAQ Data
     *         Key_Week, list of dates in the TAQ Data
     *         Key_Week_Ex, list of all possible week-exchange combinations in TAQ Data
     */
    proc sql;
        create table Key_Ex     as select distinct Ex,                   1 as key from Exchange_Weekly_Volume;
        create table Key_Week   as select distinct Week,                 1 as key from Exchange_Weekly_Volume;
        create table Key_Week_Ex
        as select
        a.Week, b.ex, 1 as key
        from Key_Week as a
        full join Key_Ex as b
        on a.key = b.key;
    quit;
    
    /*
     * INPUT: Exchange_Weekly_Volume, week-exchange volume
     *        Key_Week_Ex, list of all possible exchange-date combinations in TAQ Data
     * 
     * This merges the date-exchange volume dataset onto Key_Date_Ex, the list of all possible exchange-date combinations.
     * Exchange-date combinations that did not experience trading get a volume of 0.
     * 
     * OUTPUT: Exchange_Weekly_Volume_All, week-exchange volume
     */
    proc sql;
        create table Exchange_Weekly_Volume_All
        as select
        a.*,
        b.Volume_S,
        b.Volume_D
        from Key_Week_Ex as a
        left join Exchange_Weekly_Volume as b
         on a.week       = b.week
          & a.ex         = b.ex;
    quit;
    /** 
     * INPUT: Exchange_Weekly_Volume, week-exchange volume
     * 
     * Calculates the volume shares by dividing each exchange's volume by the total volume executed that week.
     * 
     * OUTPUT: Raw_Weekly_Shares_2007_2018, week-exchange volume and volume shares
     */
    proc sql;
        create table Ex_Weekly_Shares_&period.
        as select
        a.week,
        a.ex,
        a.Volume_S,
        a.Volume_D,
        a.Volume_S   / sum(a.Volume_S)   as Regular_Sh_S,
        a.Volume_D   / sum(a.Volume_D)   as Regular_Sh_D
        from Exchange_Weekly_Volume_All as a
        group by week;
    quit;
  
    /* Export to the user directory */
    data tempdir.Ex_Weekly_Shares_&period.;
        set Ex_Weekly_Shares_&period.;
    run;
  
    /* Export to the user directory as a csv */
    proc export data=Ex_Weekly_Shares_&period.
        outfile = "&user_path./Ex_Weekly_Shares_&period..csv"
        dbms = csv replace;
    run;

%Mend;

/*
 * _MACRO_ : Exchange_Shares(period_start, period_end)
 * 
 * PARAM: period_start, the first year of the observation period
 *        period_end, the last year of the observation period
 *
 * REQUIRES: All Exchange_Shares Macros
 *
 * Exchange_Shares builds the daily and weekly volume share data for the period specified by 
 * "period_start" and "period_end" by running all the previous macros.
 *
 */
%Macro Exchange_Shares(period_start, period_end);

    %let year_ending = _&period_end.;
    %let interval = &period_start.&year_ending.;

    %PeriodExchangeVolume(&period_start., &period_end.);
    %Compile_Period_Volume(&Start_year_input., &End_year_input.);
    %Daily_Volume_Shares(&interval.);
    %Weekly_Volume_Shares(&interval.);

%Mend;
    
/**********************************************************************************
 * ______________________________________RUN______________________________________*
 **********************************************************************************/

%Exchange_Shares(&Start_year_input., &End_year_input.);
